package com.kaili.common.aop;

import com.alibaba.fastjson.JSONObject;
import com.kaili.common.aop.log.enums.FunctionName;
import com.kaili.common.aop.log.LogObjectHolder;
import com.kaili.common.aop.log.bean.AbstractLogDict;
import com.kaili.common.aop.log.bean.OperateLogBean;
import com.kaili.common.aop.log.enums.LogType;
import com.kaili.common.aop.log.enums.OperateType;
import com.kaili.common.response.CommonStatus;
import com.kaili.common.util.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>功能描述：AOP记录操作日志</p>
 * <p>Copyright: Copyright (c) 2017</p>
 * <p>Company: 杭州凯立通信有限公司</p>
 *
 * @author PF0P65Z6
 * @version 1.0 2018年1月10日 上午10:10:35
 */
@Aspect
@Component
public class OperateLogAop {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private LogAsyncTask logAsyncTask;

    /**
     * controller层切点
     */
    @Pointcut(value = "@annotation(com.kaili.common.aop.OperateLogAspect)")
    public void controllerAspect() {
    }

    /**
     * 环绕通知 用于拦截controller层，记录用户的操作日志
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("controllerAspect()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = point.proceed();

        if(result instanceof CommonStatus){
            if(200 != ((CommonStatus)result).value()){
                return result;
            }
        }

        try {
            handle(point);
        } catch (Exception e) {
            logger.error("AOP写日志报错!", e);
        }

        return result;
    }

    /**
     * 记录操作日志的业务处理
     *
     * @param point
     * @throws Exception
     */
    private void handle(ProceedingJoinPoint point) throws Exception {
        //AOP拦截记录操作日志
        Signature sig = point.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Object target = point.getTarget();
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());

        //获取拦截方法的参数
        Object[] params = point.getArgs();
        String[] paramNames = ((CodeSignature)point.getSignature()).getParameterNames();
        Map<String, String> obj2 = new HashMap<String,String>();
        for(int i = 0 ; i < paramNames.length ; i++){
            obj2.put(paramNames[i],String.valueOf(params[i]));
        }
        if (params != null && params.length > 0) {
            obj2.putAll(ReflectUtil.objectToMap(params[0]));
        }

        //获取操作名称
        OperateLogAspect annotation = currentMethod.getAnnotation(OperateLogAspect.class);
        FunctionName functionName = annotation.functionName();
        OperateType operateType = annotation.operateType();
        String key = annotation.key();
        Class dictClass = annotation.dict();

        //如果涉及到修改,比对变化
        JSONObject msgJsonObj = null;
        AbstractLogDict logDict = (AbstractLogDict) dictClass.newInstance();
        if (OperateType.UPDATE.equals(operateType)) {
            Object obj1 = LogObjectHolder.me().get();
            if (obj1 != null) {
                msgJsonObj = CompareUtil.compareObj(dictClass, key, obj1, obj2);
            } else {
                msgJsonObj = CompareUtil.parseKey(logDict, key, obj2);
            }
        } else {
            msgJsonObj = CompareUtil.parseKey(logDict, key, obj2);
        }
//        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//        String ipAddr = HttpUtil.getIpAddr(request);

        //日志写入mongodb
        OperateLogBean logBean = new OperateLogBean();
        logBean.setKey(CompareUtil.getKey(logDict, key, obj2));
        logBean.setFunctionName(functionName.getCode());
        logBean.setOperateType(operateType.getCode());
        logBean.setLogType(LogType.OPERATE.getCode());
        logBean.setCreateByName(LoginDetailUtils.getUserName());
        logBean.setCreateTime(new Date());
        logBean.setSiteName(LoginDetailUtils.getSiteName());
        logBean.setMsg(msgJsonObj.toJSONString());

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String collectionName = CommonUtil.getMongodbName(request);
        logAsyncTask.saveLog(logBean, collectionName);
    }
}